package com.github.cakin.shiro.spring;

import org.apache.shiro.web.filter.mgt.FilterChainManager;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;

import javax.servlet.FilterChain;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.util.ArrayList;
import java.util.List;

/**
 * @className: CustomPathMatchingFilterChainResolver
 * @description: 定制PathMatchingFilterChainResolver
 * 和默认的 PathMatchingFilterChainResolver 区别是，此处得到所有匹配的拦截器链，
 * 然后通过调用 CustomDefaultFilterChainManager.proxy(originalChain, chainNames) 进行合并后代理。
 * @date: 2020/5/28
 * @author: cakin
 */
public class CustomPathMatchingFilterChainResolver extends PathMatchingFilterChainResolver {
    /**
     * 定义customDefaultFilterChainManager
     */
    private CustomDefaultFilterChainManager customDefaultFilterChainManager;
    /**
     * 功能描述：通过配置注入CustomDefaultFilterChainManager
     *
     * @author cakin
     * @date 2020/5/28
     * @param 
     * @return 
     * @description:
     */
    public void setCustomDefaultFilterChainManager(CustomDefaultFilterChainManager customDefaultFilterChainManager) {
        this.customDefaultFilterChainManager = customDefaultFilterChainManager;
        setFilterChainManager(customDefaultFilterChainManager);
    }
    /**
     * 功能描述：得到所有匹配的拦截器链
     *
     * @author cakin
     * @date 2020/5/28
     * @param request 请求
     * @param response 响应
     * @param originalChain 原始过滤器链
     * @return FilterChain 代理过滤器链
     */
    public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain) {
        // 首先获取拦截器链管理器
        FilterChainManager filterChainManager = getFilterChainManager();
        if (!filterChainManager.hasChains()) {
            return null;
        }
        // 获取当前请求的URL
        String requestURI = getPathWithinApplication(request);
        // 定义拦截器链的名称列表
        List<String> chainNames = new ArrayList<String>();
        // 循环拦截器管理器中的拦截器定义（拦截器链的名字就是URL模式）
        for (String pathPattern : filterChainManager.getChainNames()) {

            // 当前URL匹配拦截器名字（URL模式）
            if (pathMatches(pathPattern, requestURI)) {
                // 将匹配的拦截器链的名称加入到chainNames中
                chainNames.add(pathPattern);
            }
        }

        if(chainNames.size() == 0) {
            return null;
        }
        // 返回所有匹配的拦截器链，proxy的作用就是合并所有的拦截器链
        FilterChain proxy = customDefaultFilterChainManager.proxy(originalChain, chainNames);
        /**
              <value>
                  /login = authc
                  /logout = logout
                  /unauthorized.jsp = authc
                  /** = user,sysUser
              </value>
         当配置如上，执行 http://localhost:8080/chapter19/unauthorized.jsp 此时变量如下：
         chainNames = {ArrayList@7827}  size = 2
         0 = "/unauthorized.jsp"
         1 = "/**"
         proxy = {ProxiedFilterChain@7828}
         orig = {ServletHandler$CachedChain@7825} "jsp"
         filters = {SimpleNamedFilterList@7832}  size = 3
         0 = {FormAuthenticationFilter@7781} "authc"
         1 = {UserFilter@7782} "user"
         2 = {SysUserFilter@7783} "sysUser"
         可见过滤器链是合并后的,这样做的目的是让所有能匹配的过滤器链中的过滤器都能执行到，而不仅仅是只匹配第一个过滤器链
         */
        return proxy;
    }
}
